package org.infoset.xml.memory;

import java.io.*;
import java.util.*;
import java.net.*;

import org.infoset.xml.*;


public abstract class MemoryItem implements Item {

   static class FollowingSiblings implements Iterator {
      Child context;
      FollowingSiblings(Child sibling) {
         this.context = sibling;
      }
      public boolean hasNext() {
         return context!=null;
      }

      public void remove() {
         throw new UnsupportedOperationException("remove() cannot be called while iterating an axis.");
      }

      public Object next() {
         if (context==null) {
            return null;
         }
         Child toReturn = context;
         context = context.getFollowingSibling();
         return toReturn;
      }
   }

   static class PreviousSiblings implements Iterator {
      Child context;
      PreviousSiblings(Child sibling) {
         this.context = sibling;
      }
      public boolean hasNext() {
         return context!=null;
      }

      public void remove() {
         throw new UnsupportedOperationException("remove() cannot be called while iterating an axis.");
      }

      public Object next() {
         if (context==null) {
            return null;
         }
         Child toReturn = context;
         context = context.getPrecedingSibling();
         return toReturn;
      }
   }

   protected double ranking;
   protected Parent origin;
   protected Infoset infoset;

   protected MemoryItem(Infoset infoset,double ranking,Parent origin) {
      this.infoset = infoset;
      this.ranking = ranking;
      this.origin = origin;
   }

   protected abstract void setIndex(int i);

   public Infoset getInfoset() {
      return infoset;
   }
   
   public Parent getOrigin() {
      return origin;
   }

   public Document getDocument() {
      if (this instanceof Document) {
         return (Document)this;
      } else {
         return origin.getDocument();
      }
   }

   public int compareTo(Item other) {
      // TODO: fails for cross document compares -- will affect XSLT implementatoins
      // TODO: take into account different documents.... see above

      if (other instanceof Attribute) {
         other = other.getOrigin();
      }

      Item self = this;

      // If an attribute, use the parent element
      if (this instanceof Attribute) {
         self = getOrigin();
         // If the comparison is to the parent element, the attribute is afterwards.
         if (self==other) {
            return 1;
         }
      }

      /*
      try {
      System.err.println("other.rank="+((MemoryItem)other).getRank()+",this.rank="+((MemoryItem)self).getRank());
      System.err.print("other='");
      PrintWriter pw = new PrintWriter(System.err);
      other.write(pw);
      pw.flush();
      System.err.println("'");
      System.err.print("this.='");
      write(pw);
      pw.flush();
      System.err.println("'");
      } catch (java.io.IOException ex) {
	 ex.printStackTrace();
      }
      */
      if (other==self) {
         return 0;
      }
      return ((MemoryItem)other).getRank()>((MemoryItem)self).getRank() ? -1 : 1;
   }

   double getRank() {
      return ranking;
   }

   protected void setRank(double value) {
      ranking = value;
   }
   
   void setOrigin(Parent newOrigin) {
      origin = newOrigin;
   }

   public String getGeneratedId() { 
      // TODO: implement unique id
      return "n"+ranking;
   }

   public Iterator getAxis(Infoset.Axis type) {
      return Collections.EMPTY_LIST.iterator();
   }
   
}
